package com.ce.pms.base.dao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.ce.util.StringUtil;

/**
 * 1.0 仅支持模糊,精确查询, 区间比较以及排序的SQL拼装
 *
 * @author yzw
 *
 */
public class QueryCondition {

	public static final String SQL_MATCH_ANY = "%"; //

	public static final int ORDER_DESC = OrderEntry.ORDER_DESC;

	public static final int ORDER_ASC = OrderEntry.ORDER_ASC;

	private int pageNo = 1;

	private int pageSize = 0;

	//	 模糊匹配
	private Map condition;

	//	 精确匹配
	private Map equalsConditions;

    //	 区间比较
    protected Map betweenConditions;

    //  排序
	private List orderby;

	public String toString() {
		return null;
	}

	public QueryCondition() {

	}

	// ////////////////////////////////////////////////////////////////////////
	public void put(Object key, Object value) {
		condition = checkMap(condition);
		condition.put(key, value);
	}

	public void equals(Object key, Object value) {
		equalsConditions = checkMap(equalsConditions);
		equalsConditions.put(key, value);
	}

	public void between(Object key, BetweenEntry be) {
		betweenConditions = checkMap(betweenConditions);
		betweenConditions.put(key, be);
	}

	public String buildSql(List valList, String alias) {
		StringBuffer countSql = new StringBuffer();
		countSql.append("1=1");

		appendConditionQuery(countSql, alias, valList);
		appendEqualsConditions(countSql, alias, valList);
		appendBetweenQueryCondition(countSql, alias, valList);

		//		 TODO????排序
		countSql.append(appendOrderbyCondition(alias));
		return countSql.toString();
	}

	/**
	 * 顺序排序 先调用本方法的key将在前面排序，后调用本方法的key将在后面排序
	 *
	 * @param key
	 *            the order name
	 * @param direction
	 *            the direction of this order, acse or desc
	 */
	public void orderSequence(Object key, int direction) {
		OrderEntry oe = new OrderEntry(key, direction);
		orderby = checkList(orderby);
		if (orderby.contains(oe)) {
			orderby.remove(oe);
		}
		orderby.add(new OrderEntry(key, direction));
	}

	public void orderSequenceAsc(Object key) {
		orderSequence(key, OrderEntry.ORDER_ASC);
	}

	public void orderSequenceDesc(Object key) {
		orderSequence(key, OrderEntry.ORDER_DESC);
	}

	/**
	 * 倒序排序。 先调用本方法的key将在后面排序，后调用本方法的key将在前面排序
	 *
	 * @param key
	 *            the order name
	 * @param direction
	 *            the direction of this order, acse or desc
	 */
	public void order(Object key, int direction) {
		OrderEntry oe = new OrderEntry(key, direction);
		orderby = checkList(orderby);
		if (orderby.contains(oe)) {
			orderby.remove(oe);
		}
		orderby.add(0, new OrderEntry(key, direction));
	}

	public void orderAsc(Object key) {
		order(key, OrderEntry.ORDER_ASC);
	}

	public void orderDesc(Object key) {
		order(key, OrderEntry.ORDER_DESC);
	}

	// ///////////////////////////////////////////////////////
	private void appendConditionQuery(StringBuffer countSql, String alias,
			List valList) {
		Map condMap = getConditions();
		if (condMap == null)
			return;
		for (Iterator it = condMap.entrySet().iterator(); it.hasNext();) {
			Map.Entry condEntry = (Map.Entry) it.next();
			String condKey = (String) condEntry.getKey();
			Object condVal = condEntry.getValue();
			if (null != condVal) {
				Object val;
				if (condVal instanceof String) {
					//TODO 对于字符串类型进行模糊检索
					val = new StringBuffer().append(SQL_MATCH_ANY).append(
							condVal).append(SQL_MATCH_ANY).toString();
					countSql.append(" and ").append(alias).append(".").append(
							condKey).append(" like ? ");
					valList.add(val);

				} else {
					val = condVal;
					countSql.append(" and ").append(alias).append(".").append(
							condKey).append("=? ");
					valList.add(val);
				}
			}
		}
	}

	private void appendEqualsConditions(StringBuffer countSql,
			final String alias, List valList) {
		Map equalsMap = getEqualsConditions();
		if (equalsMap == null)
			return;

		for (Iterator it = equalsMap.entrySet().iterator(); it.hasNext();) {
			Map.Entry equalsEntry = (Map.Entry) it.next();
			String condKey = (String) equalsEntry.getKey();
			Object condVal = equalsEntry.getValue();
			if (null != condVal) {
				ConditionHandler handler = new ConditionHandler() {
					public void addSql(StringBuffer sb, String alias, String key) {
						sb.append(alias).append(".").append(key).append("=? ");
					}

					public boolean needVal() {
						return true;
					}
				};
				handleCondition(condVal, condKey, alias, valList, countSql,
						handler);
			}
		}
		return;
	}

	private void handleCondition(Object condVal, Object condKey, String alias,
			List valList, StringBuffer countSql, ConditionHandler handler) {
		String key = condKey.toString();
		countSql.append(" and ");
		handler.addSql(countSql, alias, key);
		if (handler.needVal()) {
			valList.add(condVal);
		}
	}

	private String appendOrderbyCondition(final String alias) {
		List orderList = getOrders();
		StringBuffer sb = new StringBuffer();

		if (null != orderList) {
			for (int i = 0; i < orderList.size(); i++) {
				OrderEntry orderEntry = (OrderEntry) orderList.get(i);
				String orderKey = (String) orderEntry.getKey();
				if (StringUtil.isEmpty(orderKey)) {
					continue;
				}
				int direction = orderEntry.getDirection();
				if (OrderEntry.ORDER_DESC == direction
						|| OrderEntry.ORDER_ASC == direction) {
					if (sb.length() == 0) {
						sb.append(" ORDER BY ");

					}
					sb.append(" ").append(alias).append(".").append(orderKey)
							.append(" ").append(OrderEntry.ORDER_DESC).append(
									",");
				}
			}
			//TODO????过滤尾巴","
			if (sb.lastIndexOf(",") == sb.length() - 1)
				return sb.substring(0, sb.length() - 1).toString();
			else
				return sb.toString();
		}
		return "";
	}

	public void appendBetweenQueryCondition(
			StringBuffer countSql, String alias, List valList) {
		Map betweenMap = getBetweenConditions();
		if (betweenMap == null)
			return ;
		for (Iterator it = betweenMap.entrySet().iterator(); it.hasNext();) {
			Map.Entry condEntry = (Map.Entry) it.next();
			String condKey = (String) condEntry.getKey();
			BetweenEntry condVal = (BetweenEntry) condEntry.getValue();
			if (null != condVal) {
				countSql.append(" and ").append(alias).append(".").append(
						condKey).append(" between ? and ? ");
				valList.add(condVal.getObject1());
				valList.add(condVal.getObject2());
			}
		}
	}

	public int getPageNo() {
		return pageNo;
	}

	public void setPageNo(int pageNo) {
		this.pageNo = pageNo;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	private Map getConditions() {
		return condition;
	}

	private Map getEqualsConditions() {
		return equalsConditions;
	}

	public Map getBetweenConditions() {
		return betweenConditions;
	}

	public void setBetweenConditions(Map betweenConditions) {
		this.betweenConditions = betweenConditions;
	}

	private List getOrders() {
		return orderby;
	}

	private Map checkMap(Map map) {
		if (map == null)
			return new HashMap();
		return map;
	}

	private List checkList(List list) {
		if (list == null)
			return new ArrayList();
		return list;
	}

	interface ConditionHandler {
		public void addSql(StringBuffer sb, String alias, String key);

		public boolean needVal();
	}

	public static void main(String[] arg) {
		String target1 = "alias.fieldA like ? and alias.fieldB like ?";
		String target2 = "alias.fieldC=? and alias.fieldD=?";
		String target3 = "order by alias.fieldE 1, alias.fieldF -1";
		try {

			StringBuffer countSql = new StringBuffer();
			List valList = new ArrayList();
			QueryCondition qc = new QueryCondition();

			qc.setPageSize(1);
			qc.setPageNo(10);
			qc.put("fieldA", "xxx");
			qc.put("fieldB", 1);
			System.out.println(target1);
			System.out.println(qc.buildSql(valList, "alias"));
			System.out.println(valList);
			valList.clear();

			qc = new QueryCondition();
			qc.equals("fieldC", "xxx");
			qc.equals("fieldD", 1);
			System.out.println(target2);
			System.out.println(qc.buildSql(valList, "alias"));
			System.out.println(valList);
			valList.clear();

			qc = new QueryCondition();
			qc.equals("fieldC", "xxx");
			qc.equals("fieldD", 1);
			System.out.println(target2);
			System.out.println(qc.buildSql(valList, "alias"));
			System.out.println(valList);
			valList.clear();

			qc = new QueryCondition();
			qc.order("fieldE", OrderEntry.ORDER_ASC);
			qc.order("fieldF", OrderEntry.ORDER_DESC);
			System.out.println(target3);
			System.out.println(qc.buildSql(valList, "alias"));
			System.out.println(valList);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
